package com.chukun.spring.dependency.lookup;

import com.chunkun.ioc.domain.User;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 *  @author chukun
 *  类型安全 依赖查找示例
 */
public class TypeSafetyDependencyLookupDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 将当前类 ObjectProviderDemo 作为配置类（Configuration Class）
        applicationContext.register(TypeSafetyDependencyLookupDemo.class);

        // 启动应用上下文
        applicationContext.refresh();

        // 演示 BeanFactory#getBean 方法的安全性，不安全
        displayBeanFactoryGetBean(applicationContext);
        // 演示 ObjectFactory#getObject 方法的安全性，不安全
        displayObjectFactoryGetObject(applicationContext);

        // 演示 ObjectProvider#getIfAvaiable 方法的安全性 安全
        displayObjectProviderIfAvailable(applicationContext);

        // 演示 ListableBeanFactory#getBeansOfType 方法的安全性,安全
        displayListableBeanFactoryGetBeansOfType(applicationContext);
        // 演示 ObjectProvider Stream 操作的安全性,安全
        displayObjectProviderStreamOps(applicationContext);

        // 关闭应用上下文
        applicationContext.close();

    }

    /**
     * 安全
     * @param applicationContext
     */
    private static void displayObjectProviderStreamOps(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
        printBeansException("displayObjectProviderStreamOps", () -> userObjectProvider.forEach(System.out::println));
    }

    /**
     * 安全
     * @param applicationContext
     */
    private static void displayListableBeanFactoryGetBeansOfType(AnnotationConfigApplicationContext applicationContext) {
         ListableBeanFactory listableBeanFactory = applicationContext.getDefaultListableBeanFactory();
         printBeansException("displayListableBeanFactoryGetBeansOfType",() -> listableBeanFactory.getBeansOfType(User.class));
    }

    /**
     * 安全
     * @param applicationContext
     */
    private static void displayObjectProviderIfAvailable(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
        printBeansException("displayObjectProviderIfAvailable",() -> userObjectProvider.getIfAvailable());
    }

    /**
     * 不安全
     * @param beanFactory
     */
    private static void displayBeanFactoryGetBean(BeanFactory beanFactory) {
        printBeansException("displayBeanFactoryGetBean",() -> beanFactory.getBean(User.class));
    }

    /**
     * 不安全
     * @param beanFactory
     */
    private static void displayObjectFactoryGetObject(BeanFactory beanFactory) {
        ObjectProvider<User> beanProvider = beanFactory.getBeanProvider(User.class);
        printBeansException("displayObjectFactoryGetObject",() -> beanProvider.getObject());
    }

    /**
     * 打印异常
     * @param message
     * @param r
     */
    private static void printBeansException(String message, Runnable r) {
        System.err.println("================================");
        System.err.println("source from : "+message);
        try {
            r.run();
        }catch (BeansException exception) {
            exception.printStackTrace();
        }
    }
}
